#include "tests.h"
#include<iostream>
using namespace std;
// 练习1，实现库函数strlen
int my_strlen(char *str) {
    /**
     * 统计字符串的长度，太简单了。
     */

    // IMPLEMENT YOUR CODE HERE
    if(*str!='\0'){
        return my_strlen(str+1)+1;
    }
    else{
        return 0;
    }
}


// 练习2，实现库函数strcat
void my_strcat(char *str_1, char *str_2) {
    /**
     * 将字符串str_2拼接到str_1之后，我们保证str_1指向的内存空间足够用于添加str_2。
     * 注意结束符'\0'的处理。
     */

    // IMPLEMENT YOUR CODE HERE
    int i=my_strlen(str_1),j=0;
    while(1){
        str_1[i]=str_2[j];
        if(j==my_strlen(str_2))break;
        i++;
        j++;
    }
}


// 练习3，实现库函数strstr
char* my_strstr(char *s, char *p) {
    /**
     * 在字符串s中搜索字符串p，如果存在就返回第一次找到的地址，不存在就返回空指针(0)。
     * 例如：
     * s = "123456", p = "34"，应该返回指向字符'3'的指针。
     */
    int n=0;
    for(int i=0;i<my_strlen(s);i++){
        for(int j=0;j<my_strlen(p);j++){
            if(s[i+j]!=p[j]){
                break;
            }
            else{
                n++;
            }
        }
        if(n==my_strlen(p)){
            return s+i;
        }
    }
    // IMPLEMENT YOUR CODE HERE
    return 0;
}


/**
 * ================================= 背景知识 ==================================
 * 1. 什么是图片？
 *    图片可以看做是由像素组成的一个方阵，图片分成两种，一种是灰度图片，颜色只有黑白
 * 两种，一种是彩色图片。
 *    灰度图片的每一个像素是一个范围在[0, 255]内的数值，数值越高就越接近白色。
 *    彩色图片的每一个像素都是一个长度为3的数组，数组中的每一个元素都是[0, 255]内的
 * 数值，3个数的含义分别是Red, Green, Blue，表示这个像素所在的位置这3种颜色的强度，
 * 举个例子，纯红色对应的像素就是{255, 0, 0}。这3个数称为图片的3个通道，这种像素表示
 * 方式也称之为图片的RGB表示方式。
 *
 * 2. 图片的属性？
 *    图片是一个方阵，所以具有宽、高两个属性，除此之外还有一个通道数，比如说灰度图片
 * 的通道数为1，RGB彩色图片的通道数为3。图片的宽高也称为图片的分辨率。
 *
 * 3. 图片在计算机中如何存储？
 *   灰度图片可以看成是二维数组，为方便计算，数据类型使用float。举个例子：
 *   float a[2][3] = {
 *      {121, 231, 35},
 *      {47, 52, 63}
 *   };
 *   就可以看做是一个高为2，宽为3的灰度图片。实际上图片的宽高都比较大，比如说500。
 *
 *   彩色图片也可以看作是由像素构成的二维数组，举个例子，一张高为2，宽为3彩色图片在
 * 内存中的存储为：
 *
 *   低地址 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - >>> 高地址
 *
 *    R    G    B    R    G    B    R    G    B    R    G    B    R    G    B    R    G    B
 *   111, 123, 215, 233, 123, 142, 156, 233, 267, 223, 234, 175, 123, 117, 168, 123, 156, 156
 *   |< -------- >| |< -------- >| |< -------- >| |< -------- >| |< -------- >| |< -------- >|
 *     第一个像素      第二个像素      第三个像素       第四个像素     第五个像素     第六个像素
 *   |< -------------------------------------- >| |< -------------------------------------- >|
 *                    第一行像素                                   第二行像素
 *
 *   理解了图片的存储之后，再开始编写代码。
 */


// 练习4，将彩色图片(rgb)转化为灰度图片
void rgb2gray(float *in, float *out, int h, int w) {
    /**
     * 编写这个函数，将一张彩色图片转化为灰度图片。以下是各个参数的含义：
     * (1) float *in:  指向彩色图片对应的内存区域（或者说数组）首地址的指针。
     * (2) float *out: 指向灰度图片对应的内存区域（或者说数组）首地址的指针。
     * (3) int h:      height，即图片的高度。
     * (4) int w:      width，即图片的宽度。
     *
     * 提示：
     * (1) in数组只管读取就行了，别修改它的值。out数组只修改不读取。
     * (2) 利用公式 V = 0.1140 * B  + 0.5870 * G + 0.2989 * R 计算彩色图片每个
     *     像素对应的灰度值，写到灰度图片相同的位置中就行。
     * (3) 使用for循环来遍历每个位置。利用图片在内存中的存储顺序，计算出每个位置像素
     *     的地址。
     *
     * 考点：
     * (1) for循环的使用。
     * (2) 内存的访问。
     */

    // IMPLEMENT YOUR CODE HERE

    int n=0;
    for(int i=0;i<h;i++){
        for(int j=0;j<w;j++){
            n++;
            *(out+n)=*(in+3*n)*0.2989+*(in+1+3*n)*0.5870+*(in+2+3*n)*0.1140;
        }
    }
    // ...
}
// 练习5，实现图像处理算法 resize：缩小或放大图像
void resize(float *in, float *out, int h, int w, int c, float scale) {
    int new_h = h * scale, new_w = w * scale;
    int m=0;
    // IMPLEMENT YOUR CODE HERE
    for(int i=0;i<new_h;i++){
        for(int j=0;j<new_w;j++){
                float y0=i/scale;
                float x0=j/scale;
                int x1=static_cast<int>(x0);
                int y1=static_cast<int>(y0);//i0,j0
            for(int k=0;k<3;k++){
                if(x1==new_w||y1==new_h){
                    int x2=x1,y2=y1;
                    int p1=*(in+y1*w*3+x2*3+k),p2=*(in+y2*w*3+x2*3+k),p3=*(in+y1*w*3+x1*3+k),p4=*(in+y2*w*3+x1*3+k);
                    float dx=x0-x1,dy=y0-y1;
                    *(out+k+3*j+new_w*i*3)=p1*(1-dx)*(1-dy)+p2*dx*(1-dy)+p3*(1-dx)*dy+p4*dx*dy;
                }
                else{
                    int x2=x1+3+k,y2=y1+1+k;
                    int p1=*(in+y1*w*3+x2*3+k),p2=*(in+y2*w*3+x2*3+k),p3=*(in+y1*w*3+x1*3+k),p4=*(in+y2*w*3+x1*3+k);
                    float dx=x0-x1,dy=y0-y1;
                    *(out+k+3*j+new_w*i*3)=p1*(1-dx)*(1-dy)+p2*dx*(1-dy)+p3*(1-dx)*dy+p4*dx*dy;
                }
                
            }
        }
    }

}


// 练习6，实现图像处理算法：直方图均衡化
void hist_eq(float *in, int h, int w) {
    /**
     * 将输入图片进行直方图均衡化处理。参数含义：
     * (1) float *in: 输入的灰度图片。
     * (2) int h:     height，即图片的高度。
     * (3) int w:      width，即图片的宽度。
     *
     * 参考资料：
     * https://blog.csdn.net/qq_15971883/article/details/88699218
     * 其它的博客也行。
     *
     * 提示：
     * (1) 输入图片是灰度图，每个像素值是[0, 255]内的小数
     * (2) 灰度级个数为256，也就是{0, 1, 2, 3, ..., 255}
     * (3) 使用数组来实现灰度级 => 灰度级的映射
     */

    // IMPLEMENT YOUR CODE HERE
    double nk[256]={0},N=h*w;
    for(int i=0;i<256;i++){
        for(int j=0;j<N;j++){
            if(*(in+j)==i){
                nk[i]++;
            }
        }
    }
    double prk[256]={0},sn[256]={0};
    for(int i=0;i<256;i++){
        prk[i]=nk[i]/N;
    }
    for(int i=0;i<256;i++){
        for(int j=0;j<=i;j++){
            sn[i]+=prk[j];
        }
    }
    for(int i=0;i<256;i++){
        sn[i]=sn[i]*255;
    }
    int snPlus[256]={0};
    for(int i=0;i<256;i++){
        snPlus[i]=sn[i]*10;
    }
    for(int i=0;i<256;i++){
        if(snPlus[i]%10>=5){
            snPlus[i]=(snPlus[i]/10)+1;
        }
        else{
            snPlus[i]=(snPlus[i]/10);
        }
    }
    
    for(int i=0;i<N;i++){
        int k=*(in+i);
        *(in+i)=snPlus[k];
    }

}
